/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.form; import java.awt.*; import java.beans.*; import java.lang.reflect.Method; import java.util.*; import java.text.MessageFormat; import javax.swing.*; import org.openide.*; import org.openide.awt.*; import org.openide.explorer.*; import org.openide.windows.*; import org.openide.explorer.propertysheet.PropertySheetView; import org.openide.explorer.propertysheet.PropertySheet; import org.openide.explorer.view.BeanTreeView; import org.openide.nodes.Node; import org.openide.util.HelpCtx; import org.netbeans.modules.form.util2.NbVersion; import org.netbeans.modules.form.actions.*; import org.netbeans.modules.form.FormDataObject; import org.netbeans.modules.form.FormLoaderSettings; import org.netbeans.modules.form.palette.*; import org.netbeans.modules.form.compat2.layouts.*; import org.netbeans.modules.form.compat2.layouts.support.*; /** A static class that manages global FormEditor issues. * * @author Ian Formanek */ final public class FormEditor extends Object { // ----------------------------------------------------------------------------- // Static variables /** The global version number of the FormEditor serialized format */ public static final NbVersion FORM_EDITOR_VERSION = new NbVersion (1, 0); /** The prefix for event properties. The name of an event property * is a concatenation of this string and the event name. * E.g. for mousePressed event, the property is named "__EVENT__mousePressed" */ public static final String EVENT_PREFIX = "__EVENT__"; // NOI18N /** The prefix for component's layout properties. The name of such property * is a concatenation of this string and the component layout property's name. * E.g. for Direction layout property, the property is named "__LAYOUT__mousePressed" */ public static final String LAYOUT_PREFIX = "__LAYOUT__"; // NOI18N public static final String GUI_EDITING_WORKSPACE_NAME = "Visual"; // NOI18N /** The resource bundle for the form editor */ private static java.util.ResourceBundle formBundle = org.openide.util.NbBundle.getBundle (FormEditor.class); /** Settings of FormEditor */ private static FormLoaderSettings formSettings = new FormLoaderSettings (); /** The DesignMode action */ private static DesignModeAction designModeAction = new DesignModeAction (); /** The TestMode action */ private static TestModeAction testModeAction = new TestModeAction (); /** The action that holds the curent palette state (selection/add mode) */ private static PaletteAction paletteAction = new PaletteAction (); /** The default width of the ComponentInspector */ public static final int DEFAULT_INSPECTOR_WIDTH = 250; /** The default height of the ComponentInspector */ public static final int DEFAULT_INSPECTOR_HEIGHT = 400; /** The default percents of the splitting of the ComponentInspector */ public static final int DEFAULT_INSPECTOR_PERCENTS = 30; /** The default width of the form window */ public static final int DEFAULT_FORM_WIDTH = 300; /** The default height of the form window */ public static final int DEFAULT_FORM_HEIGHT = 200; static ExplorerActions actions = new ExplorerActions (); // --------------------------------------------------- // Private static variables /** * @associates ErrorLogItem */ private static ArrayList errorLog = new ArrayList (); private static ComponentInspector componentInspector; private static EmptyInspectorNode emptyInspectorNode; /** Default icon base for control panel. */ private static final String EMPTY_INSPECTOR_ICON_BASE = "/org/netbeans/modules/form/resources/emptyInspector"; // NOI18N // ----------------------------------------------------------------------------- // Static methods /** Provides the resource bundle for FormEditor */ public static java.util.ResourceBundle getFormBundle() { return formBundle; } /** Provides the settings for the FormEditor */ public static FormLoaderSettings getFormSettings () { return formSettings; } /** Provides the shared PaletteAction */ public static PaletteAction getPaletteAction () { return paletteAction; } public static ComponentInspector getComponentInspector() { if (componentInspector == null) { componentInspector = new ComponentInspector (); } return componentInspector; } public static PropertyEditor createPropertyEditor (Class editorClass, Class propertyType, RADComponent radComponent, RADComponent.RADProperty radProperty) throws InstantiationException, IllegalAccessException { PropertyEditor ed; if (editorClass.equals (RADConnectionPropertyEditor.class)) { ed = new RADConnectionPropertyEditor (propertyType); } else { ed = (PropertyEditor)editorClass.newInstance (); } if (ed instanceof FormAwareEditor) { ((FormAwareEditor)ed).setRADComponent (radComponent, radProperty); } if (ed instanceof org.openide.explorer.propertysheet.editors.NodePropertyEditor) { ((org.openide.explorer.propertysheet.editors.NodePropertyEditor)ed).attach (new org.openide.nodes.Node[] { radComponent.getNodeReference () }); } return ed; } public static java.awt.Image getGridImage (Container gridCont) { Image gridImage = gridCont.createImage(100, 100); Graphics ig = gridImage.getGraphics(); ig.setColor(gridCont.getBackground ()); ig.fillRect(0, 0, 100, 100); ig.setColor(gridCont.getForeground()); for (int j=0; j< 100; j+= 10) for (int i=0; i< 100; i+= 10) ig.drawLine(i,j,i,j); return gridImage; } public static String getSerializedBeanName (RADComponent comp) { StringBuffer name = new StringBuffer (comp.getFormManager ().getFormObject ().getName ()); name.append ("$"); // NOI18N name.append (comp.getName ()); name.append (".ser"); // NOI18N return name.toString (); } public static void defaultComponentInit (RADComponent radComp) { Object comp = radComp.getBeanInstance (); String varName = radComp.getName (); String propName = null; Object propValue = null; if (comp instanceof Button) { if ("".equals (((Button)comp).getLabel ())) { // NOI18N propName = "label"; // NOI18N propValue = varName; } } else if (comp instanceof Checkbox) { if ("".equals (((Checkbox)comp).getLabel ())) { // NOI18N propName = "label"; // NOI18N propValue = varName; } } else if (comp instanceof Label) { if ("".equals (((Label)comp).getText ())) { // NOI18N propName = "text"; // NOI18N propValue = varName; } } else if (comp instanceof TextField) { if ("".equals (((TextField)comp).getText ())) { // NOI18N propName = "text"; // NOI18N propValue = varName; } } else if (comp instanceof AbstractButton) { // JButton, JToggleButton, JCheckBox, JRadioButton if ("".equals (((AbstractButton)comp).getText ())) { // NOI18N propName = "text"; // NOI18N propValue = varName; } } else if (comp instanceof JLabel) { if ("".equals (((JLabel)comp).getText ())) { // NOI18N propName = "text"; // NOI18N propValue = varName; } } else if (comp instanceof JTable) { javax.swing.table.TableModel tm = ((JTable)comp).getModel (); if ((tm == null) || ((tm instanceof javax.swing.table.DefaultTableModel) && (tm.getRowCount () == 0) && (tm.getColumnCount () == 0))) { propValue = new org.netbeans.beaninfo.editors.TableModelEditor.NbTableModel (new javax.swing.table.DefaultTableModel ( new String[] {"Title 1", "Title 2", "Title 3", "Title 4"}, // NOI18N 4 )); propName = "model"; // NOI18N } } else if ((comp instanceof JTextField) && (!(comp instanceof JPasswordField))) { // JTextField and not JPasswordField if ("".equals (((JTextField)comp).getText ())) { // NOI18N propName = "text"; // NOI18N propValue = varName; } } if (propName != null) { RADComponent.RADProperty prop = radComp.getPropertyByName (propName); if (prop != null) { try { prop.setValue (propValue); } catch (IllegalAccessException e) { // never mind, ignore } catch (java.lang.reflect.InvocationTargetException e) { // never mind, ignore } } } } public static void defaultMenuInit (RADMenuItemComponent menuComp) { Object comp = menuComp.getBeanInstance (); String varName = menuComp.getName (); String propName = null; Object propValue = null; if (comp instanceof MenuItem) { if ("".equals (((MenuItem)comp).getLabel ())) { // NOI18N String value = "{0}"; // NOI18N propName = "label"; // NOI18N if (comp instanceof PopupMenu) { value = formBundle.getString("FMT_LAB_PopupMenu"); } else if (comp instanceof Menu) { value = formBundle.getString("FMT_LAB_Menu"); } else if (comp instanceof CheckboxMenuItem) { value = formBundle.getString("FMT_LAB_CheckboxMenuItem"); } else { value = formBundle.getString("FMT_LAB_MenuItem"); } propValue = MessageFormat.format(value, new Object[] { varName }); } } else if (comp instanceof JMenuItem) { if ("".equals (((JMenuItem)comp).getText ())) { // NOI18N String value = "{0}"; // NOI18N propName = "text"; // NOI18N if (comp instanceof JCheckBoxMenuItem) { value = formBundle.getString("FMT_LAB_JCheckBoxMenuItem"); } else if (comp instanceof JMenu) { value = formBundle.getString("FMT_LAB_JMenu"); } else if (comp instanceof JRadioButtonMenuItem) { value = formBundle.getString("FMT_LAB_JRadioButtonMenuItem"); } else { value = formBundle.getString("FMT_LAB_JMenuItem"); } propValue = MessageFormat.format(value, new Object[] { varName }); } } if (propName != null) { RADComponent.RADProperty prop = menuComp.getPropertyByName (propName); if (prop != null) { try { prop.setValue (propValue); } catch (IllegalAccessException e) { // never mind, ignore } catch (java.lang.reflect.InvocationTargetException e) { // never mind, ignore } } } } public static boolean isNonReflectedProperty (Class clazz, PropertyDescriptor desc) { if ("visible".equals (desc.getName ())) return true; // NOI18N else { if (Window.class.isAssignableFrom (clazz)) { if ("enabled".equals (desc.getName ())) return true; // NOI18N else if ("modal".equals (desc.getName ())) return true; // NOI18N } } return false; } /** A method that returns the supporting layout for some containers, which * have a special design-time support in the FormEditor. * @param itemClass The class of the component the layout is requested for * @return the DesignLayout that should be used in the container. */ public static DesignSupportLayout getSupportLayout (Class itemClass) { if (javax.swing.JTabbedPane.class.isAssignableFrom (itemClass)) return new JTabbedPaneSupportLayout (); else if (javax.swing.JScrollPane.class.isAssignableFrom (itemClass)) return new JScrollPaneSupportLayout (); else if (java.awt.ScrollPane.class.isAssignableFrom (itemClass)) return new ScrollPaneSupportLayout (); else if (javax.swing.JSplitPane.class.isAssignableFrom (itemClass)) return new JSplitPaneSupportLayout (); else if (javax.swing.JLayeredPane.class.isAssignableFrom (itemClass)) return new JLayeredPaneSupportLayout (); return null; } /** @return The DesignLayout support for container represented by this PaletteNode, or * null, if this PaletteNode does not represent a Container or there is no design-time * support for the layout of the container */ public static DesignLayout findDesignLayout (PaletteItem item) { if (!item.isContainer ()) return null; Class itemClass = item.getItemClass (); DesignSupportLayout supportLayout = getSupportLayout (itemClass); if (supportLayout != null) return supportLayout; Object sharedInstance = null; try { sharedInstance = item.getSharedInstance (); } catch (Exception e) { } if (sharedInstance == null) { return null; // in the case when creation of new instance fails, we just return null // to say, that we do not provide a design-time layout for such bean } DesignLayout newDesignLayout = null; Container container = null; try { Object value = item.getBeanInfo ().getBeanDescriptor ().getValue ("containerDelegate"); // NOI18N if ((value != null) && (value instanceof String) && ((String)value).equals ("getContentPane")) { // NOI18N Method m = sharedInstance.getClass ().getMethod ("getContentPane", new Class [0]); // NOI18N container = (Container) m.invoke (sharedInstance, new Object [0]); } } catch (Exception e) { // effectively ignored - simply no containerDelegate } if (container == null) container = (Container)sharedInstance; LayoutManager lm = container.getLayout(); if (lm != null) { if (lm instanceof FlowLayout) { newDesignLayout = new DesignFlowLayout (); } else if (lm instanceof BorderLayout) { newDesignLayout = new DesignBorderLayout (); } else if (lm instanceof CardLayout) { newDesignLayout = new DesignCardLayout (); } else if (lm instanceof GridLayout) { newDesignLayout = new DesignGridLayout (); } else if (lm instanceof GridBagLayout) { newDesignLayout = new DesignGridBagLayout (); } else if (lm instanceof EqualFlowLayout) { newDesignLayout = new DesignEqualFlowLayout (); } else if (lm instanceof org.netbeans.lib.awtextra.AbsoluteLayout) { newDesignLayout = new DesignAbsoluteLayout (); } else if (lm instanceof BoxLayout) { newDesignLayout = new DesignBoxLayout (); } // [PENDING - dynamic layouts search] /* Class layoutClass = getDesignLayout(lm.getClass()); try { newDesignLayout = (DesignLayout)layoutClass.newInstance(); } catch (Exception e) { // if problem occurs ==>> null layout newDesignLayout = null; } */ } return newDesignLayout; } static RADComponent.RADProperty[] sortProperties (java.util.List properties, Class beanClass) { return (RADComponent.RADProperty[])properties.toArray (new RADComponent.RADProperty[properties.size ()]); // noop so far [PENDING] } // --------------------------------------------------- // inner classes /** The ComponentInspector explorer */ final public static class ComponentInspector extends ExplorerPanel implements java.io.Serializable { /** The message formatter for Explorer title */ private static java.text.MessageFormat formatInspectorTitle = new java.text.MessageFormat ( formBundle.getString ("FMT_InspectorTitle") ); /** A JDK 1.1. serial version UID */ // static final long serialVersionUID = 6802346985641760699L; /** Currently focused form or null if no form is opened/focused */ transient private FormManager2 formManager; /** The Inspector's icon */ private final static java.awt.Image inspectorIcon = java.awt.Toolkit.getDefaultToolkit ().getImage ( ComponentInspector.class.getResource ("/org/netbeans/modules/form/resources/inspector.gif")); // NOI18N static final long serialVersionUID =4248268998485315927L; ComponentInspector () { final ExplorerManager manager = getExplorerManager (); emptyInspectorNode = new EmptyInspectorNode (); manager.setRootContext (emptyInspectorNode); PropertySheetView sheet; SplittedPanel split = new SplittedPanel(); split.add (new BeanTreeView(), SplittedPanel.ADD_FIRST); split.add (sheet = new PropertySheetView(), SplittedPanel.ADD_SECOND); split.setSplitType(org.openide.awt.SplittedPanel.VERTICAL); split.setSplitPosition(DEFAULT_INSPECTOR_PERCENTS); sheet.setDisplayWritableOnly (getFormSettings ().getDisplayWritableOnly ()); add ("Center", split); // NOI18N manager.addPropertyChangeListener (new PropertyChangeListener () { public void propertyChange (PropertyChangeEvent evt) { if (ExplorerManager.PROP_SELECTED_NODES.equals (evt.getPropertyName ())) { updateTitle (); if (formManager != null) { formManager.updateSelection (getExplorerManager ().getSelectedNodes ()); } } } } ); setIcon (inspectorIcon); setName (formBundle.getString ("CTL_NoSelection")); } public void open (Workspace workspace) { Workspace realWorkspace = TopManager.getDefault ().getWindowManager ().getCurrentWorkspace (); Workspace visualWorkspace = TopManager.getDefault().getWindowManager().findWorkspace(GUI_EDITING_WORKSPACE_NAME); Mode ourMode = realWorkspace.findMode(this); if ((ourMode == null) && workspace.equals(visualWorkspace)) { // create new mode for CI and set the bounds properly ourMode = workspace.createMode("ComponentInspector", getName (), null); //NOI18N Rectangle workingSpace = workspace.getBounds(); ourMode.setBounds(new Rectangle (workingSpace.x + (workingSpace.width * 3 / 10), workingSpace.y, workingSpace.width * 2 / 10, workingSpace.height / 2)); ourMode.dockInto(this); } super.open(workspace); } public HelpCtx getHelpCtx () { return getHelpCtx (getExplorerManager ().getSelectedNodes (), new HelpCtx (ComponentInspector.class)); } public void focusForm (FormManager2 formManager) { //System.out.println("Focus Form: "+formManager); // NOI18N this.formManager = formManager; designModeAction.setFormManager (formManager); testModeAction.setFormManager (formManager); if (formManager == null) { getExplorerManager ().setRootContext (emptyInspectorNode); } else { getExplorerManager ().setRootContext (formManager.getFormEditorSupport ().getFormRootNode ()); } } FormManager2 getFocusedForm () { return formManager; } void setSelectedNodes (Node[] nodes, FormManager2 manager) throws java.beans.PropertyVetoException { if (manager == formManager) { getExplorerManager ().setSelectedNodes (nodes); } } Node[] getSelectedNodes () { return getExplorerManager ().getSelectedNodes (); } /** Called when the explored context changes. * The default implementation updates the title of the window. */ protected void updateTitle () { Node[] nodes = getExplorerManager ().getSelectedNodes(); String title; if (nodes.length == 0) title = formBundle.getString ("CTL_NoSelection"); else if (nodes.length == 1) { RADComponentCookie cookie = (RADComponentCookie)nodes[0].getCookie (RADComponentCookie.class); if (cookie != null) { RADComponent radComponent = cookie.getRADComponent (); title = formatInspectorTitle.format ( new Object[] { radComponent.getName() } ); } else { title = formBundle.getString ("CTL_NoSelection"); } } else title = formBundle.getString ("CTL_MultipleSelection"); setName (title); } /** Fixed preferred size, so as the inherited preferred size is too big */ public Dimension getPreferredSize () { return new Dimension (DEFAULT_INSPECTOR_WIDTH, DEFAULT_INSPECTOR_HEIGHT); } /** replaces this in object stream */ public Object writeReplace() { return new ResolvableHelper (); } } final public static class ResolvableHelper implements java.io.Serializable { static final long serialVersionUID =7424646018839457544L; public Object readResolve() { return FormEditor.getComponentInspector (); } } static class EmptyInspectorNode extends org.openide.nodes.AbstractNode { public EmptyInspectorNode () { super (org.openide.nodes.Children.LEAF); setIconBase (EMPTY_INSPECTOR_ICON_BASE); } public boolean canRename () { return false; } } final static class ErrorLogItem { public static final int WARNING = 0; public static final int ERROR = 1; public ErrorLogItem (String desc, Throwable t) { this (desc, t, ERROR); } public ErrorLogItem (String desc, Throwable t, int type) { thr = t; this.type = type; this.desc = desc; } String getDescription () { return desc; } Throwable getThrowable () { return thr; } int getType () { return type; } private String desc; private int type; private Throwable thr; } static void clearLog () { errorLog.clear (); } public static void fileError (String desc, Throwable t) { errorLog.add (new ErrorLogItem (desc, t, ErrorLogItem.ERROR)); } public static void fileWarning (String desc, Throwable t) { errorLog.add (new ErrorLogItem (desc, t, ErrorLogItem.WARNING)); } public static void displayErrorLog () { if (errorLog.size () == 0) return; ErrorLogDialog eld = new ErrorLogDialog ((ErrorLogItem[])errorLog.toArray (new ErrorLogItem[errorLog.size ()])); errDlg = TopManager.getDefault ().createDialog (new DialogDescriptor ( eld, FormEditor.getFormBundle ().getString ("CTL_ErrorsNotificationTitle"), true, new Object[] { FormEditor.getFormBundle ().getString ("CTL_CLOSE") }, FormEditor.getFormBundle ().getString ("CTL_CLOSE"), DialogDescriptor.BOTTOM_ALIGN, null, new java.awt.event.ActionListener() { public void actionPerformed (java.awt.event.ActionEvent evt) { errDlg.setVisible (false); } } ) ); errDlg.show (); clearLog (); } private static java.awt.Dialog errDlg; } /* * Log * 47 Gandalf-post-FCS1.45.1.0 3/15/00 David Simonek japanese localization * now works correctly (workspace setting) * 46 Gandalf 1.45 1/15/00 Pavel Buzek * 45 Gandalf 1.44 1/15/00 Ian Formanek I18N * 44 Gandalf 1.43 1/13/00 Ian Formanek NOI18N #2 * 43 Gandalf 1.42 1/12/00 Pavel Buzek I18N * 42 Gandalf 1.41 1/11/00 Pavel Buzek * 41 Gandalf 1.40 1/5/00 Ian Formanek NOI18N * 40 Gandalf 1.39 12/8/99 Pavel Buzek FormEditor and * ComponentInspector windows open on Visual workspace * 39 Gandalf 1.38 11/5/99 Jesse Glick Context help jumbo * patch. * 38 Gandalf 1.37 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 37 Gandalf 1.36 9/24/99 Ian Formanek sortProperties is back * 36 Gandalf 1.35 9/24/99 Ian Formanek Rollback of last * erroneous checkin * 35 Gandalf 1.34 9/23/99 Ian Formanek Better notification in * case that the JAR Archive does not contain any JavaBeans. * 34 Gandalf 1.33 9/12/99 Ian Formanek FormAwareEditor.setRADComponent * changes * 33 Gandalf 1.32 9/9/99 Ian Formanek AbsoluteLayout changes * 32 Gandalf 1.31 9/2/99 Ian Formanek Reflecting changes in * RADComponent.getPropertyByName * 31 Gandalf 1.30 8/10/99 Ian Formanek Generated Serial Version * UID * 30 Gandalf 1.29 8/3/99 Ian Formanek Default JTable model * init * 29 Gandalf 1.28 8/1/99 Ian Formanek NodePropertyEditor * employed * 28 Gandalf 1.27 8/1/99 Ian Formanek createPropertyEditor * method, fixed title of COmponentInspector after deserialization * 27 Gandalf 1.26 7/20/99 Jesse Glick Context help. * 26 Gandalf 1.25 7/12/99 Ian Formanek Fixed to compile * 25 Gandalf 1.24 7/9/99 Ian Formanek Menu editor improvements * 24 Gandalf 1.23 7/5/99 Ian Formanek getComponentInstance->getBeanInstance, * getComponentClass->getBeanClass * 23 Gandalf 1.22 6/25/99 Ian Formanek Constants for default * form size * 22 Gandalf 1.21 6/24/99 Jesse Glick Gosh-honest HelpID's. * 21 Gandalf 1.20 6/22/99 Ian Formanek employed DEFAULT_HELP * 20 Gandalf 1.19 6/9/99 Ian Formanek ---- Package Change To * org.openide ---- * 19 Gandalf 1.18 6/4/99 Ian Formanek Fixed component * inspector icon * 18 Gandalf 1.17 6/4/99 Ian Formanek * 17 Gandalf 1.16 6/2/99 Ian Formanek ToolsAction, Reorder * 16 Gandalf 1.15 5/31/99 Ian Formanek Design/Test Mode * 15 Gandalf 1.14 5/24/99 Ian Formanek * 14 Gandalf 1.13 5/20/99 Ian Formanek FormNodeCookie->RADComponentCookie * * 13 Gandalf 1.12 5/16/99 Ian Formanek Persistence * failure-proofness improved * 12 Gandalf 1.11 5/16/99 Ian Formanek * 11 Gandalf 1.10 5/15/99 Ian Formanek * 10 Gandalf 1.9 5/15/99 Ian Formanek * 9 Gandalf 1.8 5/14/99 Ian Formanek * 8 Gandalf 1.7 5/14/99 Ian Formanek * 7 Gandalf 1.6 5/12/99 Ian Formanek * 6 Gandalf 1.5 5/4/99 Ian Formanek Package change * 5 Gandalf 1.4 5/2/99 Ian Formanek * 4 Gandalf 1.3 4/7/99 Ian Formanek Backward-compatible * deserialization finalized for Gandalf beta * 3 Gandalf 1.2 3/24/99 Ian Formanek * 2 Gandalf 1.1 3/24/99 Ian Formanek * 1 Gandalf 1.0 3/24/99 Ian Formanek * $ */